import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from sklearn.utils import shuffle

"""
多元线性回归模型
y = x1*w1 + x2*w2 + ... + x12*w12 + b
波士顿房价预测
"""

'''读取数据文件'''
df = pd.read_csv("boston.csv", header=0)
# 显示数据摘要描述信息
print(df.describe())

# 获取df的值
df = df.values
# 把df转化为np的数组格式
df = np.array(df)

'''数据归一化'''
for i in range(12):
    df[:, i] = df[:, i] / (df[:, i].max() - df[:, i].min())

# x_data为前12列的特征数据
x_data = df[:, :12]
# y_data为最后一列标签数据
y_data = df[:, 12]

'''构建模型'''
# 定义占位符 [行数, 列数]
# 12个特征数据(12列)
x = tf.compat.v1.placeholder(tf.float32, [None, 12], name="X")
# 1个特征数据(1列)
y = tf.compat.v1.placeholder(tf.float32, [None, 1], name="Y")

# 定义一个命名空间
with tf.compat.v1.name_scope("Model"):
    # w初始化为shape=(12,1)的随机数
    w = tf.compat.v1.Variable(tf.compat.v1.random_normal([12, 1], stddev=0.01, name="W"))
    # b 初始化为1.0
    b = tf.compat.v1.Variable(1.0, name="B")


    def model(x, w, b):
        """ w和x是矩阵相乘, 用matmul不能用multiply或者*
        利用矩阵相乘 y = x1*w1 + x2*w2 + x3*w3 + b转化为
                            [w1]
        y =  [x1, x2, x3] * [w2] + b
                            [w3]
        """
        return tf.compat.v1.matmul(x, w) + b


    # 预测计算操作, 前向计算节点
    prep = model(x, w, b)

'''训练模型'''
# 迭代轮次
train_epochs = 50
# 学习率
learn_rate = 0.01

# 定义损失函数(均方差)
with tf.compat.v1.name_scope("LossFunction"):
    loss_function = tf.compat.v1.reduce_mean(tf.pow(y - prep, 2))

# 创建优化器
optimizer = tf.compat.v1.train.GradientDescentOptimizer(learn_rate).minimize(loss_function)

# 声明会话
sess = tf.compat.v1.Session()
# 定义初始化操作
init = tf.compat.v1.global_variables_initializer()
# 启动会话
sess.run(init)

# 迭代训练
for epoch in range(train_epochs):
    loss_sum = 0.0
    for xs, ys in zip(x_data, y_data):
        # feed数据必须和placeholder的shape一致
        xs = xs.reshape(1, 12)
        ys = ys.reshape(1, 1)
        _, loss = sess.run([optimizer, loss_function], feed_dict={x: xs, y: ys})
        loss_sum += loss
    # 打乱数据顺序
    x_values, y_values = shuffle(x_data, y_data)
    b0temp = b.eval(session=sess)
    w0temp = w.eval(session=sess)
    loss_average = loss_sum / len(y_data)

    print("epoch=", epoch + 1, "loss=", loss_average, "b=", b0temp, "w=", w0temp)
